using Microsoft.AspNetCore.Mvc;
using SG3L_RAG.Application.DTOs;
using SG3L_RAG.Application.Interfaces;
using System.Text;
using System.Text.Json;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Parser;

namespace SG3L_RAG.Api.Controllers
{
    /// <summary>
    /// 聊天控制器
    /// 提供混合模式智能问答功能，支持纯文本、图片OCR、文档上传等多种输入方式
    /// 通过Server-Sent Events (SSE) 实现流式响应
    /// </summary>
    [ApiController]
    [Route("api/[controller]")]
    public class ChatController : ControllerBase
    {
        private readonly IChatService _chatService;
        private readonly ILogger<ChatController> _logger;
        private readonly HttpClient _httpClient;
        private readonly IConfiguration _configuration;
        
        // 百度OCR配置
        private readonly string _baiduApiKey;
        private readonly string _baiduSecretKey;
        private readonly string _baiduOcrUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic";

        public ChatController(
            IChatService chatService, 
            ILogger<ChatController> logger,
            HttpClient httpClient,
            IConfiguration configuration)
        {
            _chatService = chatService;
            _logger = logger;
            _httpClient = httpClient;
            _configuration = configuration;
            _baiduApiKey = configuration["BaiduOCR:ApiKey"] ?? "";
            _baiduSecretKey = configuration["BaiduOCR:SecretKey"] ?? "";
        }

        /// <summary>
        /// 发送消息并获取AI回复
        /// </summary>
        /// <param name="request">聊天请求</param>
        /// <returns>AI回复</returns>
        [HttpPost("ask")]
        public async Task<ActionResult<ChatResponseDto>> AskQuestion([FromBody] ChatRequestDto request)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(request.Question))
                {
                    return BadRequest(new { error = "问题不能为空" });
                }

                if (request.UserId == Guid.Empty)
                {
                    return BadRequest(new { error = "用户ID不能为空" });
                }

                _logger.LogInformation("收到聊天请求，用户ID: {UserId}, 问题长度: {QuestionLength}",
                    request.UserId, request.Question.Length);

                var response = await _chatService.AskQuestionAsync(request);

                if (response.IsSuccessful)
                {
                    return Ok(response);
                }
                else
                {
                    return BadRequest(new { error = response.ErrorMessage });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理聊天请求时发生错误");
                return StatusCode(500, new { error = "服务器内部错误" });
            }
        }

        /// <summary>
        /// 流式聊天接口，支持文件上传和图片OCR
        /// </summary>
        /// <param name="question">问题</param>
        /// <param name="userId">用户ID</param>
        /// <param name="files">文件集合（包含文档和图片）</param>
        /// <param name="useRAG">是否使用RAG</param>
        /// <param name="maxResults">最大结果数</param>
        /// <param name="similarityThreshold">相似度阈值</param>
        /// <returns>流式AI回复</returns>
        [HttpPost("ask-stream-files")]
        [Consumes("multipart/form-data")]
        public async Task AskQuestionStreamWithFiles(
            [FromForm] string question,
            [FromForm] string userId,
            [FromForm] string? conversationId = null, // 添加conversationId参数
            [FromForm] IFormFileCollection? files = null,
            [FromForm] bool useRAG = true,
            [FromForm] int maxResults = 5,
            [FromForm] float similarityThreshold = 0.7f)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(question))
                {
                    await WriteStreamError("问题不能为空");
                    return;
                }

                if (!Guid.TryParse(userId, out var userGuid) || userGuid == Guid.Empty)
                {
                    await WriteStreamError("用户ID不能为空或格式无效");
                    return;
                }

                // 设置SSE响应头
                Response.Headers["Content-Type"] = "text/event-stream";
                Response.Headers["Cache-Control"] = "no-cache";
                Response.Headers["Connection"] = "keep-alive";
                Response.Headers["Access-Control-Allow-Origin"] = "*";
                Response.Headers["Access-Control-Allow-Headers"] = "Cache-Control";

                _logger.LogInformation("收到流式聊天请求，用户ID: {UserId}, 问题长度: {QuestionLength}, 文件数量: {FileCount}",
                    userGuid, question.Length, files?.Count ?? 0);

                // 发送开始事件
                await WriteStreamEvent("start", new { message = "开始处理请求" });

                // 处理上传的文件
                var documentContents = new List<string>();
                var fileInfos = new List<object>();
                
                if (files != null && files.Count > 0)
                {
                    await WriteStreamEvent("processing", new { message = $"正在解析 {files.Count} 个上传文件..." });

                    foreach (var file in files)
                    {
                        try
                        {
                            if (file.Length > 0)
                            {
                                using var memoryStream = new MemoryStream();
                                await file.CopyToAsync(memoryStream);
                                var fileContent = memoryStream.ToArray();

                                string parsedContent = "";
                                
                                // 检查文件类型
                                var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
                                var isImageFile = new[] { ".jpg", ".jpeg", ".png", ".bmp" }.Contains(fileExtension);
                                
                                if (isImageFile)
                                {
                                    // 图片文件 - 使用OCR识别
                                    await WriteStreamEvent("processing", new { message = $"正在识别图片 {file.FileName} 中的文字..." });
                                    
                                    parsedContent = await ExtractTextFromImage(fileContent);
                                    
                                    if (!string.IsNullOrWhiteSpace(parsedContent))
                                    {
                                        documentContents.Add($"图片 {file.FileName} 识别的文字内容:\n{parsedContent}");
                                        fileInfos.Add(new
                                        {
                                            fileName = file.FileName,
                                            fileSize = file.Length,
                                            fileType = "图片(OCR)",
                                            contentLength = parsedContent.Length,
                                            status = "OCR识别成功"
                                        });
                                    }
                                    else
                                    {
                                        fileInfos.Add(new
                                        {
                                            fileName = file.FileName,
                                            fileSize = file.Length,
                                            fileType = "图片(OCR)",
                                            contentLength = 0,
                                            status = "OCR识别失败，未识别到文字"
                                        });
                                    }
                                }
                                else
                                {
                                    // 文档文件 - 使用文档解析
                                    await WriteStreamEvent("processing", new { message = $"正在解析文档 {file.FileName}..." });
                                    
                                    parsedContent = await ParseFileContent(fileContent, file.FileName);
                                    
                                    if (!string.IsNullOrWhiteSpace(parsedContent))
                                    {
                                        documentContents.Add($"文件 {file.FileName} 内容:\n{parsedContent}");
                                        fileInfos.Add(new
                                        {
                                            fileName = file.FileName,
                                            fileSize = file.Length,
                                            fileType = "文档",
                                            contentLength = parsedContent.Length,
                                            status = "解析成功"
                                        });
                                    }
                                    else
                                    {
                                        fileInfos.Add(new
                                        {
                                            fileName = file.FileName,
                                            fileSize = file.Length,
                                            fileType = "文档",
                                            contentLength = 0,
                                            status = "解析失败，不支持的文件格式或文件损坏"
                                        });
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "处理文件 {FileName} 时发生错误", file.FileName);
                            fileInfos.Add(new
                            {
                                fileName = file.FileName,
                                fileSize = file.Length,
                                fileType = "错误",
                                contentLength = 0,
                                status = $"处理失败: {ex.Message}"
                            });
                        }
                    }

                // 发送文件处理结果
                await WriteStreamEvent("files_processed", new { files = fileInfos });
            }

            // 构建完整的问题（包含文档内容）
            var fullQuestion = question;
            if (documentContents.Any())
            {
                fullQuestion = $"{question}\n\n相关文件内容:\n{string.Join("\n\n", documentContents)}";
            }

            // 解析conversationId (如果提供)
            Guid? conversationGuid = null;
            if (!string.IsNullOrWhiteSpace(conversationId) && Guid.TryParse(conversationId, out var tempGuid))
            {
                    conversationGuid = tempGuid;
                }

                // 创建聊天请求
                var chatRequest = new ChatRequestDto
                {
                    Question = fullQuestion,
                    UserId = userGuid,
                    ConversationId = conversationGuid, // 传递前端提供的conversationId
                    UseRAG = useRAG,
                    MaxResults = maxResults,
                    SimilarityThreshold = similarityThreshold
                };

                // 发送到聊天服务
                await WriteStreamEvent("ai_thinking", new { message = "AI正在思考..." });

                var response = await _chatService.AskQuestionAsync(chatRequest);

                if (response.IsSuccessful)
                {
                    // 模拟流式输出
                    var answer = response.Answer ?? "";
                    var chunkSize = 50; // 每次发送50个字符
                    
                    for (int i = 0; i < answer.Length; i += chunkSize)
                    {
                        var chunk = answer.Substring(i, Math.Min(chunkSize, answer.Length - i));
                        await WriteStreamEvent("message", new { chunk = chunk });
                        await Task.Delay(100); // 模拟延迟
                    }

                    await WriteStreamEvent("complete", new 
                    { 
                        message = "回答完成",
                        sources = response.Sources?.Select(s => s.Excerpt).ToList() ?? new List<string>(),
                        confidence = response.ConfidenceScore
                    });
                }
                else
                {
                    await WriteStreamError(response.ErrorMessage ?? "处理请求时发生错误");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "流式聊天处理失败");
                await WriteStreamError($"服务器内部错误: {ex.Message}");
            }
        }

        #region OCR功能

        /// <summary>
        /// 从图片中提取文字 (OCR)
        /// </summary>
        /// <param name="imageContent">图片内容</param>
        /// <returns>提取的文字</returns>
        private async Task<string> ExtractTextFromImage(byte[] imageContent)
        {
            try
            {
                if (string.IsNullOrEmpty(_baiduApiKey) || string.IsNullOrEmpty(_baiduSecretKey))
                {
                    _logger.LogWarning("百度OCR API密钥未配置");
                    return "OCR功能未配置，请联系管理员配置百度OCR API密钥";
                }

                // 获取访问令牌
                var accessToken = await GetBaiduAccessToken();
                if (string.IsNullOrEmpty(accessToken))
                {
                    _logger.LogError("获取百度API访问令牌失败");
                    return "获取OCR访问令牌失败，请稍后重试";
                }

                // 调用百度OCR API
                return await CallBaiduOCR(imageContent, accessToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "OCR识别过程中发生错误");
                return $"OCR识别失败: {ex.Message}";
            }
        }

        /// <summary>
        /// 获取百度API访问令牌
        /// </summary>
        private async Task<string> GetBaiduAccessToken()
        {
            try
            {
                var tokenUrl = $"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={_baiduApiKey}&client_secret={_baiduSecretKey}";
                
                var response = await _httpClient.GetAsync(tokenUrl);
                var content = await response.Content.ReadAsStringAsync();
                
                if (response.IsSuccessStatusCode)
                {
                    var tokenResponse = JsonSerializer.Deserialize<JsonElement>(content);
                    if (tokenResponse.TryGetProperty("access_token", out var token))
                    {
                        return token.GetString() ?? "";
                    }
                }
                
                _logger.LogError($"获取百度访问令牌失败: {content}");
                return "";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取百度访问令牌异常");
                return "";
            }
        }

        /// <summary>
        /// 调用百度OCR API
        /// </summary>
        private async Task<string> CallBaiduOCR(byte[] imageContent, string accessToken)
        {
            try
            {
                // 将图片转换为Base64
                var base64Image = Convert.ToBase64String(imageContent);

                // 构建请求参数
                var requestData = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("image", base64Image),
                    new KeyValuePair<string, string>("language_type", "CHN_ENG"), // 中英文混合
                    new KeyValuePair<string, string>("detect_direction", "true"), // 检测图像朝向
                    new KeyValuePair<string, string>("paragraph", "false"), // 是否输出段落信息
                    new KeyValuePair<string, string>("probability", "false") // 是否返回识别结果中每一行的置信度
                };

                var formContent = new FormUrlEncodedContent(requestData);
                
                // 发送请求
                var requestUrl = $"{_baiduOcrUrl}?access_token={accessToken}";
                var response = await _httpClient.PostAsync(requestUrl, formContent);
                var content = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    var ocrResponse = JsonSerializer.Deserialize<JsonElement>(content);
                    
                    if (ocrResponse.TryGetProperty("words_result", out var wordsResult))
                    {
                        var extractedLines = new List<string>();
                        
                        foreach (var word in wordsResult.EnumerateArray())
                        {
                            if (word.TryGetProperty("words", out var wordsText))
                            {
                                var text = wordsText.GetString();
                                if (!string.IsNullOrWhiteSpace(text))
                                {
                                    extractedLines.Add(text.Trim());
                                }
                            }
                        }
                        
                        return string.Join("\n", extractedLines);
                    }
                }
                else
                {
                    _logger.LogError($"百度OCR API调用失败: {content}");
                    return $"OCR识别失败: {content}";
                }

                return "";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "调用百度OCR API异常");
                return $"OCR调用异常: {ex.Message}";
            }
        }

        #endregion

        #region 文档解析

        /// <summary>
        /// 解析文件内容
        /// </summary>
        /// <param name="content">文件内容</param>
        /// <param name="fileName">文件名</param>
        /// <returns>解析后的文本</returns>
        private Task<string> ParseFileContent(byte[] content, string fileName)
        {
            try
            {
                var extension = Path.GetExtension(fileName).ToLowerInvariant();
                
                var result = extension switch
                {
                    ".txt" or ".md" or ".html" or ".htm" or ".json" or ".xml" or ".csv" => ParseTextFile(content),
                    ".docx" => ParseDocxFile(content),
                    ".pdf" => ParsePdfFile(content),
                    ".doc" => "暂不支持 .doc 格式，请转换为 .docx 格式",
                    _ => $"不支持的文件格式: {extension}"
                };
                
                return Task.FromResult(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "解析文件 {FileName} 时发生错误", fileName);
                return Task.FromResult($"文件解析失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 解析文本文件
        /// </summary>
        private string ParseTextFile(byte[] content)
        {
            // 尝试多种编码方式
            var encodings = new[] { Encoding.UTF8, Encoding.GetEncoding("GB2312"), Encoding.ASCII, Encoding.Unicode };
            
            foreach (var encoding in encodings)
            {
                try
                {
                    var text = encoding.GetString(content);
                    
                    // 检查是否包含可读文本
                    var readableChars = text.Count(c => char.IsLetterOrDigit(c) || char.IsPunctuation(c) || char.IsWhiteSpace(c));
                    var totalChars = text.Length;
                    
                    if (totalChars > 0 && (double)readableChars / totalChars > 0.7)
                    {
                        // 清理控制字符
                        var cleanText = System.Text.RegularExpressions.Regex.Replace(text, @"[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]", " ");
                        cleanText = System.Text.RegularExpressions.Regex.Replace(cleanText, @"\s+", " ");
                        
                        return cleanText.Trim();
                    }
                }
                catch
                {
                    continue;
                }
            }
            
            return "无法解析文件内容，可能是二进制文件或不支持的编码格式";
        }

        /// <summary>
        /// 解析 .docx 文件
        /// </summary>
        private string ParseDocxFile(byte[] content)
        {
            try
            {
                using var stream = new MemoryStream(content);
                using var document = WordprocessingDocument.Open(stream, false);
                
                if (document.MainDocumentPart?.Document?.Body == null)
                {
                    return "DOCX文件格式损坏或为空";
                }

                var paragraphs = document.MainDocumentPart.Document.Body.Elements<Paragraph>();
                var textContent = new StringBuilder();

                foreach (var paragraph in paragraphs)
                {
                    var paragraphText = paragraph.InnerText;
                    if (!string.IsNullOrWhiteSpace(paragraphText))
                    {
                        textContent.AppendLine(paragraphText.Trim());
                    }
                }

                var result = textContent.ToString().Trim();
                return string.IsNullOrWhiteSpace(result) ? "DOCX文件内容为空" : result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "解析DOCX文件时发生错误");
                return $"DOCX文件解析失败: {ex.Message}";
            }
        }

        /// <summary>
        /// 解析 PDF 文件
        /// </summary>
        private string ParsePdfFile(byte[] content)
        {
            try
            {
                using var stream = new MemoryStream(content);
                using var pdfReader = new PdfReader(stream);
                using var pdfDocument = new PdfDocument(pdfReader);
                
                var textContent = new StringBuilder();
                var numberOfPages = pdfDocument.GetNumberOfPages();

                for (int i = 1; i <= numberOfPages; i++)
                {
                    var page = pdfDocument.GetPage(i);
                    var pageText = PdfTextExtractor.GetTextFromPage(page);
                    
                    if (!string.IsNullOrWhiteSpace(pageText))
                    {
                        textContent.AppendLine(pageText.Trim());
                    }
                }

                var result = textContent.ToString().Trim();
                return string.IsNullOrWhiteSpace(result) ? "PDF文件内容为空或无法提取文本" : result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "解析PDF文件时发生错误");
                return $"PDF文件解析失败: {ex.Message}";
            }
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 写入SSE事件流
        /// </summary>
        /// <param name="eventType">事件类型</param>
        /// <param name="data">数据</param>
        private async Task WriteStreamEvent(string eventType, object data)
        {
            try
            {
                var jsonData = JsonSerializer.Serialize(data, new JsonSerializerOptions 
                { 
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    WriteIndented = false
                });

                var eventData = $"event: {eventType}\ndata: {jsonData}\n\n";
                var bytes = Encoding.UTF8.GetBytes(eventData);
                
                await Response.Body.WriteAsync(bytes);
                await Response.Body.FlushAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "写入流事件时发生错误");
            }
        }

        /// <summary>
        /// 写入错误事件
        /// </summary>
        /// <param name="error">错误信息</param>
        private async Task WriteStreamError(string error)
        {
            await WriteStreamEvent("error", new { message = error });
        }

        #endregion
    }
}
